﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using Autofac;
using Autofac.Integration.WebApi;
using Newtonsoft.Json.Linq;
using Pay.Core;
using Pay.IService;
using Pay.TO;

namespace Pay.Token {
    public class AuthenticationHandler : DelegatingHandler {
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
#if DEBUG
            if (request.RequestUri.AbsoluteUri.Contains("swagger")) return await base.SendAsync(request, cancellationToken);
#endif
            try {

                HttpConfiguration configuration = request.GetConfiguration();
                HttpControllerDescriptor controllerDescriptor =
                    configuration.Services.GetHttpControllerSelector().SelectController(request);
                HttpControllerContext controllerContext = new HttpControllerContext(request.GetConfiguration(),
                                                        request.GetRouteData(), request) {
                    ControllerDescriptor = controllerDescriptor
                };
                HttpActionDescriptor actionDescriptor =
                    configuration.Services.GetActionSelector().SelectAction(controllerContext);

                //根据HttpActionDescriptor得到应用的Anonymous特性
                var atts = actionDescriptor.GetCustomAttributes<Anonymous>();
                var anonymous = atts.FirstOrDefault();


                AuthHelper authHelper = new AuthHelper();
                if (anonymous == null) {
                    var signValid = await authHelper.ValidateSign(request, cancellationToken);
                    //signValid.data = true;
                    if (!signValid.data) {
                        LogError(request, authHelper);
                        return await requestCancel(request, cancellationToken, signValid.result_msg, 600);
                    } else {
                        HttpRequestHeaders headers = request.Headers;
                        var action = actionDescriptor.ActionName.ToLower();
                        var ignore = new string[] { "login", "loginbypassword", "loginbycode", "refresh" };
                        if (headers.Authorization != null && !ignore.Contains(action)) {
                            string token = headers.Authorization.Parameter;
                            var reqScope = request.GetDependencyScope().GetRequestLifetimeScope();
                            string decodedJwt = authHelper.ValidateToken(token);
                            if (!string.IsNullOrEmpty(decodedJwt)) {
                                dynamic root = JObject.Parse(decodedJwt);
                                string user_id = root.merchant_id;
                                string username = root.iss;
                                string merchant_no = root.merchant_no;
                                #region 检查令牌对象内容
                                var claims = new List<Claim>{
                                    new Claim(ClaimTypes.NameIdentifier, user_id),
                                    new Claim(ClaimTypes.Name, username),
                                    new Claim(ClaimTypes.AuthenticationMethod, "Password")
                                };
                                if (!string.IsNullOrEmpty(merchant_no)) claims.Add(new Claim(ClaimTypes.Actor, merchant_no));
                                ClaimsPrincipal principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Bearer") });
                                Thread.CurrentPrincipal = principal;
                                if (HttpContext.Current != null) HttpContext.Current.User = principal;
                                #endregion
                                var tokenHelper = reqScope.Resolve<ITokenService>();
                                bool pool = false;
                                var obj = tokenHelper.Get(long.Parse(user_id), out pool);
                                if (!pool) {
                                    LogError(request, authHelper);
                                    return await requestCancel(request, cancellationToken, "网络异常404", 600);
                                }
                                //if (obj != null && obj.access_token == token) {
                                if (obj == null) {
                                    return await requestCancel(request, cancellationToken, "您的账户在不同设备上登录");
                                }
                            } else
                                return await requestCancel(request, cancellationToken, "401未授权");
                        }
                    }
                }

                return await base.SendAsync(request, cancellationToken); ;
            } catch {
                return await requestCancel(request, cancellationToken, "无权限访问", 402);
            }
        }

        private Task<HttpResponseMessage> requestCancel(HttpRequestMessage request,
                CancellationToken cancellationToken, string message, int code = 0) {
            CancellationTokenSource _tokenSource = new CancellationTokenSource();
            cancellationToken = _tokenSource.Token;
            _tokenSource.Cancel();
            HttpResponseMessage response = new HttpResponseMessage();
            //response = request.CreateResponse(HttpStatusCode.Unauthorized);ios和安卓接收数据只能用异常来处理，所以不要，就是200成功的
            response.Content = new StringContent(ResultToJson.Json<object>(code == 0 ? 401 : code, message, null).ToJson(), Encoding.UTF8, "application/json");
            return base.SendAsync(request, cancellationToken).ContinueWith(task => {
                return response;
            });
        }

        private void LogError(HttpRequestMessage request, AuthHelper authHelper) {
            var requestScope = request.GetDependencyScope();
            var requestLifetimeScope = requestScope.GetRequestLifetimeScope();
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Url:{0}\r\n", request.RequestUri);
            sb.AppendFormat("Method:{0}\r\n", request.Method);
            sb.AppendFormat("ContentType:{0}\r\n", request.Content.Headers.ContentType);
            sb.AppendFormat("timestamp:{0}\r\n", authHelper.timestamp);
            sb.AppendFormat("nonce:{0}\r\n", authHelper.nonce);
            sb.AppendFormat("RequestQuery:{0}\r\n", authHelper.query_str);
            sb.AppendFormat("RequestForm:{0}\r\n", authHelper.form_str);
            sb.AppendFormat("RequestOther:{0}\r\n", authHelper.other_str);
            sb.AppendFormat("sign:{0}\r\n", authHelper.sign);
            sb.AppendFormat("vSign:{0}\r\n", authHelper.vSign);
            if (request.Headers.Authorization != null)
                sb.AppendFormat("token:{0}\r\n", request.Headers.Authorization.Parameter);
            var logHelper = requestLifetimeScope.ResolveNamed<ILogHelper>("ui_error");
            logHelper.Error(sb.ToString());
        }
    }
}
